package gnss

import (
	"dgo/goutils/utils"
	"strings"
)

// / Ntrip请求解析
type NtripRequest struct {
	buffer              []byte
	position            int
	size                int
	Type                uint8
	AuthStr             string // NtripServer是接入密码
	MountPoint          string
	Headers             map[string]string
	decodestate         uint8
	headsize            int
	nmea_start_position int
	nmea_half_flag      byte // nmea接收到一半的标志
}

const (
	STATE_CLEANUP             = 0
	STATE_HEAD                = 1
	STATE_BODY                = 2
	STATE_BODY_NMEA_ENDING_1  = 3
	STATE_BODY_NMEA_ENDING_2  = 4
	STATE_BODY_NMEA_OK        = 10
	STATE_HEAD_ENDING_LINE1_1 = 5
	STATE_HEAD_ENDING_LINE1_2 = 6
	STATE_HEAD_ENDING_LINE2_1 = 7

	DECODE_HEAD = 1
	DECODE_NMEA = 2
	DECODE_ERR  = -1
)

// New returns a new initialized NtripRequest.
func NewNtripRequest() *NtripRequest {
	return &NtripRequest{
		buffer:  make([]byte, 512), // 解码数据头不需要太大, 太大可以能被攻击
		Headers: make(map[string]string),
	}
}

func (_self *NtripRequest) CleanUp() {
	_self.decodestate = 0
	for k, _ := range _self.Headers {
		delete(_self.Headers, k)
	}
}

func (_self *NtripRequest) GetSize() int {
	return _self.size
}

func (_self *NtripRequest) GetRequestType() uint8 {
	return _self.Type
}

// / 解码NtripServer头,
// /  string 第一行数据
func (_self *NtripRequest) DecodeNtripServerHeader(strs []string) int {
	if len(strs) < 3 {
		return TYPE_UNKOWN
	}
	_self.AuthStr = strs[1]
	_self.MountPoint = strings.TrimLeft(strs[2], "/")
	_self.Type = TYPE_NTRIPSERVER
	return TYPE_NTRIPSERVER
}

// / 解码NtripServer头,
// /  string 第一行数据
func (_self *NtripRequest) DecodeNtripClientAuthInfo() (id string, pass string, err error) {
	if len(_self.AuthStr) > 0 {
		decodeBytes, _ := utils.Base64Decode(_self.AuthStr)
		if len(decodeBytes) > 0 {
			s := string(decodeBytes)
			strs := strings.SplitN(s, ":", 2)
			id = strs[0]
			if len(strs) == 2 {
				pass = strs[1]
			}
		}
		return
	}
	return
}

// / 解码NtripClient头
func (_self *NtripRequest) DecodeNtripClientHeader(strHeader string) int {
	strHeaderList := strings.Split(strHeader, "\r\n")
	if len(strHeaderList) == 0 {
		return TYPE_UNKOWN
	}

	for j, str := range strHeaderList {
		if j == 0 {
			// GET / HTTP/1.0
			strFirstList := strings.Split(str, " ")
			if len(strFirstList) < 2 {
				return TYPE_UNKOWN
			}
			s := strFirstList[1]

			s = strings.TrimLeft(s, "/")

			_self.MountPoint = s
			_self.Type = TYPE_NTRIPCLIENT
		} else {
			strSecs := strings.SplitN(str, ":", 2)
			if len(strSecs) >= 2 {
				s := strings.TrimSpace(strings.ToLower(strSecs[0]))
				v := strings.TrimSpace(strSecs[1])
				_self.Headers[s] = v

				if strings.EqualFold(s, "Authorization") {
					strSecs = strings.SplitN(v, " ", 2)
					if len(strSecs) == 2 {
						_self.AuthStr = strings.TrimSpace(strSecs[1])
					}
				}
			}

		}
	}

	return TYPE_NTRIPCLIENT

}

func (_self *NtripRequest) DecodeHeader() int {
	strHeader := _self.GetHeaderString()
	if len(strHeader) < 5 {
		return TYPE_UNKOWN
	}

	i := strings.Index(strHeader, "\r\n")
	if i == -1 {
		return TYPE_UNKOWN
	}

	str1 := string([]byte(strHeader)[:i])

	if (strings.Index(str1, "SOURCE")) != -1 {
		str1list := strings.Split(str1, " ")
		return _self.DecodeNtripServerHeader(str1list)
	} else if (strings.Index(str1, "GET")) != -1 {
		return _self.DecodeNtripClientHeader(strHeader)
	}

	return TYPE_UNKOWN
}

func checkRecvHeadChar(data byte, _self *NtripRequest) {
	if data == '$' {
		_self.headsize = _self.size - 1
		_self.nmea_start_position = _self.size - 1
		_self.decodestate = STATE_BODY
	} else if data == 13 {
		// 判断是否是头部
		_self.decodestate = STATE_HEAD_ENDING_LINE1_1
	}
}

func (_self *NtripRequest) NeedMore() bool {
	if _self.decodestate == STATE_BODY { // NMEA 数据了
		return _self.nmea_half_flag == 1
	}
	return _self.decodestate != STATE_BODY_NMEA_OK && _self.size > 0

}

func (_self *NtripRequest) InputBuffer(data byte) (r int) {
	/// 初始化
	if _self.decodestate == STATE_CLEANUP {
		_self.decodestate = STATE_HEAD
		_self.position = 0
		_self.size = 0
		_self.headsize = 0
		_self.nmea_start_position = 0
		_self.nmea_half_flag = 0
	}

	if _self.decodestate == STATE_BODY_NMEA_OK {
		_self.decodestate = STATE_BODY
		_self.position = _self.headsize
		_self.size = _self.headsize
		_self.nmea_start_position = _self.headsize
		_self.nmea_half_flag = 0
	}

	if _self.size >= len(_self.buffer) {
		r = DECODE_ERR
		return
	}

	_self.buffer[_self.position] = data
	_self.position++
	_self.size++

	switch _self.decodestate {

	case STATE_HEAD:
		{ // 接收头部数据
			checkRecvHeadChar(data, _self)
			if _self.decodestate == STATE_BODY {
				if _self.headsize > 0 {
					return DECODE_HEAD
				}
			}

			if _self.size == 6 {
				str := strings.ToUpper(string(_self.buffer[:6]))
				s1 := str[:3]

				if str != "SOURCE" && s1 != "GET" {
					return DECODE_ERR
				}
			}

		}
	case STATE_BODY:
		{
			if data == '$' {
				_self.nmea_start_position = _self.size - 1
				_self.nmea_half_flag = 1
			} else if data == '*' {
				_self.decodestate = STATE_BODY_NMEA_ENDING_1
			}
		}
	case STATE_BODY_NMEA_ENDING_1:
		{
			// * 后面第一个字节
			_self.decodestate = STATE_BODY_NMEA_ENDING_2
		}
	case STATE_BODY_NMEA_ENDING_2:
		{
			_self.decodestate = STATE_BODY_NMEA_OK
			return DECODE_NMEA
		}

	case STATE_HEAD_ENDING_LINE1_1:
		{
			if data == 10 {
				_self.decodestate = STATE_HEAD_ENDING_LINE1_2
			} else {
				_self.decodestate = STATE_HEAD
				checkRecvHeadChar(data, _self)
				if _self.decodestate == STATE_BODY {
					return DECODE_HEAD
				}
			}
		}
	case STATE_HEAD_ENDING_LINE1_2:
		{
			if data == 13 {
				_self.decodestate = STATE_HEAD_ENDING_LINE2_1
			} else {
				_self.decodestate = STATE_HEAD
				checkRecvHeadChar(data, _self)
				if _self.decodestate == STATE_BODY {
					return DECODE_HEAD
				}
			}
		}
	case STATE_HEAD_ENDING_LINE2_1:
		{
			if data == 10 {
				_self.headsize = _self.size
				_self.decodestate = STATE_BODY
				return DECODE_HEAD
			} else {
				_self.decodestate = STATE_HEAD
				checkRecvHeadChar(data, _self)
				if _self.decodestate == STATE_BODY {
					return DECODE_HEAD
				}
			}
		}
	}
	return 0
}

func (_self *NtripRequest) ToString() string {
	return string(_self.buffer[:_self.size])
}

func (_self *NtripRequest) ToBytes() []byte {
	return _self.buffer[:_self.size]
}

func (_self *NtripRequest) GetHeaderString() string {
	if _self.headsize > 0 {
		return string(_self.buffer[:_self.headsize])
	} else {
		return ""
	}
}

func (_self *NtripRequest) GetBodyString() string {
	return string(_self.buffer[_self.nmea_start_position:_self.position])
}
